#include "Log.hpp"
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include "Comm.hpp"
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h>
#include <cerrno>
#include"thread.hpp"
#include"InetAddr.hpp"

using namespace std;

class ThreadData
{
    public:
        ThreadData(int sock,struct sockaddr_in& server)
        :_sockfd(sock),
        _serveraddr(server)
        {
            
        }
        ~ThreadData()
        {

        }
    public:
        int _sockfd;
        InetAddr _serveraddr;
};

void RecvRoutine(ThreadData& td)
{
    char buffer[4096];
    while(true)
    {
        //收消息

            struct sockaddr_in temp;
            socklen_t len = sizeof(temp);
            size_t n = recvfrom(td._sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &len);
 
            if (n > 0)
            {
                buffer[n] = 0;
                cerr<<buffer << endl;
            }
            else
                break;
    }
};

void SendRoutine(ThreadData& td)
{
    while(true)
    {
        // 我们要发的数据
        string inbuffer;
        cout << "Please Enter#:";
        getline(cin, inbuffer);
        //cout << inbuffer << endl;

        // 我们要发给谁?server
        auto server=td._serveraddr.GetAddr();

        int n = sendto(td._sockfd, inbuffer.c_str(), inbuffer.size(), 0, (struct sockaddr *)&server, sizeof(server));
        if(n<=0)
        cout<<"send error"<<endl;
    }
};

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        cout << "Usage:\n     ./udp_echo_client <ip> <port>" << endl;
        return -1;
    }

    string serverip = argv[1];           // 服务器ip
    uint16_t serverport = atoi(argv[2]); // 服务器端口号

    // 创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        cerr << "socket error" << strerror(errno) << endl;
        return 1;
    }

    cout << "client create socket success:" << sockfd << endl;
    // 2.客户端也需要绑定套接字空间，但是，不需要显示的绑定，client会在首次发送数据的时候自动绑定
    // 服务器的端口号，一定众所周知的，不可以随意改变，client需要port，客户端需要绑定随机端口
    // 因为客户端非常多，所以客户端需要绑定随机端口

    // 2.1填充一下server的信息
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str());

    ThreadData td(sockfd,server);
    Thread<ThreadData>recver("recver",RecvRoutine,td);
    Thread<ThreadData>sender("sender",SendRoutine,td);

   recver.Start();
   sender.Start();


    recver.Join();//主线程等待子线程
    sender.Join();


    close(sockfd);
    return 0;
}